(function () {

if (!window['DOUBAN']) { window['DOUBAN'] = {}; }

var douban = window['DOUBAN'];

douban.DoubanApi = function (api_key, api_key_secret) {
    var signature_method = "HMAC-SHA1";
    
    var request_token_uri = "http://www.douban.com/service/auth/request_token";
    var access_token_uri = "http://www.douban.com/service/auth/access_token";
    var authorization_uri = "http://www.douban.com/service/auth/authorize?oauth_token=";

    var collection_uri = "http://api.douban.com/collection";
    var user_uri = "http://api.douban.com/people/";
    var event_uri = "http://api.douban.com/event/";

    this.access_token = null;
    this.access_token_secret = null;

    this.getRequestToken = function (callback, error_callback) {
        var message = {
                method: "GET",
                action: request_token_uri,
                parameters: {
                    oauth_consumer_key: api_key,
                    oauth_signature_method: signature_method,
                    oauth_signature: "",
                    oauth_timestamp: "",
                    oauth_nonce: ""
                }
        };

        // 签名
        OAuth.setTimestampAndNonce(message);
        OAuth.SignatureMethod.sign(message, {
            consumerSecret: api_key_secret
        });

        $.ajax({
            url: message.action,
            data: OAuth.getParameterMap(message.parameters),
            type: message.method,
            success: function (data, status, xhr) {
                var responseObj = OAuth.getParameterMap(OAuth.decodeForm(data));

                request_token = responseObj.oauth_token;
                request_token_secret = responseObj.oauth_token_secret;

                callback(request_token, request_token_secret);
            },
            error: function (xhr, status, error) {
                if (error_callback) error_callback(error, status, xhr);
            }
        });
    }

    this.getUserAuthorizationURL = function (request_token) {
        return authorization_uri + request_token;
    }

    this.getAccessToken = function (request_token, request_token_secret, callback, error_callback) {
        var message = {
            method: "GET",
            action: access_token_uri,
            parameters: {
                oauth_consumer_key: api_key,
                oauth_token: request_token,
                oauth_signature_method: signature_method,
                oauth_signature: "",
                oauth_timestamp: "",
                oauth_nonce: ""
            }
        };

        OAuth.setTimestampAndNonce(message);
        OAuth.SignatureMethod.sign(message, {
            consumerSecret: api_key_secret,
            tokenSecret: request_token_secret
        });

        $.ajax({
            url: message.action,
            data: OAuth.getParameterMap(message.parameters),
            type: message.method,
            success: function (data, status, xhr) {
                var responseObj = OAuth.getParameterMap(OAuth.decodeForm(data));

                this.access_token = responseObj.oauth_token;
                this.access_token_secret = responseObj.oauth_token_secret;

                callback(this.access_token, this.access_token_secret);
            },
            error: function (xhr, status, error) {
                if (error_callback) error_callback(error, status, xhr);
            }
        });
    }

    this.sendRequest = function (url, method, data, callback, error_callback) {
        var message = {
            method: method,
            action: url.replace(/@/g, "%40"),
            parameters: {
                oauth_consumer_key: api_key,
                oauth_token: this.access_token,
                oauth_signature_method: signature_method,
                oauth_signature: "",
                oauth_timestamp: "",
                oauth_nonce: ""
            }
        }

        if (message.method == 'GET' && data) {
            message.action += '?' + $.param(data);

            data = null;
        }

        OAuth.setTimestampAndNonce(message);
        OAuth.SignatureMethod.sign(message, {
              consumerSecret: api_key_secret,
              tokenSecret: this.access_token_secret
        });

        var oauth_header = "OAuth " + ", ".join({
            realm: '""',
            oauth_consumer_key: message.parameters.oauth_consumer_key,
            oauth_nonce: message.parameters.oauth_nonce,
            oauth_timestamp: message.parameters.oauth_timestamp,
            oauth_signature_method: signature_method,
            oauth_signature: message.parameters.oauth_signature,
            oauth_token: message.parameters.oauth_token
        });

        $.ajax({
            url: message.action,
            data: data,
            type: message.method,
            headers: {
                'Authorization': oauth_header,
                'content-type': 'application/atom+xml'
            },
            success: function (data, status, xhr) {
                callback(data);
            },
            error: function (xhr, status, error) {
                if (error_callback) error_callback(error, status, xhr);
            }
        });
    }

    this.addCollection = function (port, info, callback, error_callback) {
        var dom = new xmldom.Builder('entry')
            .attr('xmlns:ns0', 'http://www.w3.org/2005/Atom')
            .attr('xmlns:db', 'http://www.douban.com/xmlns/');

        dom.elem('db:status').text(info.status);

        $.each(info.tags, function (idx, tag) {
            dom.elem('db:tag', {name: tag});
        });

        dom.elem('gd:rating', {
            value: info.rating,
            'xmlns:gd': 'http://schemas.google.com/g/2005'
        }).up().elem('content').text(info.content);

        var item = info.items.pop();

        dom.elem('db:subject')
                .elem('id').text('http://api.douban.com/' + item.category + '/subject/' + item.id);

        port.postMessage(item);

        if (info.private) {
            dom.elem('db:attribute', {name: 'privacy'}).text('private');
        }

        var xml = dom.toXml();

        //console.log(xml);

        console.log("importing " + item.name + " #" + item.id + " from doulist " + info.name + " #" + info.id);

        var api = this;

        this.sendRequest(collection_uri, "POST", xml, function (data) {
            if (info.items.length) {
                api.addCollection(port, info, callback, error_callback);
            } else {
                callback();
            }
        }, error_callback);
    }

    this.getCurrentUser = function (callback, error_callback) {
        var url = user_uri + '@me';

        this.sendRequest(url, 'GET', {alt: 'json'}, function (json) {
            var user = DOUBAN.parseUser(json);

            callback(user);
        }, error_callback)
    }

    this.getUserEvents = function (userId, action, callback, error_callback) {
        var url = user_uri + userId + '/events/' + action;
        var params = {
            alt: 'json',
            'start-index': 0,
            'max-results': 10
        };

        this.sendRequest(url, 'GET', params, function (json) {
            var events = DOUBAN.parseEvents(json);

            console.log(events);
            
            callback(events);
        }, error_callback);
    }

    this.getEvent = function (evtId, callback, error_callback) {
        var url = event_uri + evtId;

        this.sendRequest(url, 'GET', {alt: 'json'}, function (json) {
            var event = DOUBAN.parseEvent(json);

            console.log(event);

            callback(event);
        }, error_callback);
    }
}

douban.parse_url = function (url) {
    var params = {};

    var parts = url.split('?');

    if (parts.length == 2) {
        url = parts[0];

        parts = parts[1].split('&');

        for (var i=0; i<parts.length; i++) {
            var o = parts[i].split('=');

            params[o[0]] = o[1];
        }
    }

    var re = new RegExp("http://(\\w+)\.douban\.com/(\\w+)/(\\d+)/");

    var groups = url.match(re);

    if (groups == null) {
        re = new RegExp("http://www\.douban\.com/(\\w+)/(\\w+)/(\\d+)/");

        groups = url.match(re) || [];
    }

    return {
        url: url,
        params: params,
        category: groups[1],
        type: groups[2],
        id: parseInt(groups[3])
    }
}

douban.join_url = function (info) {
    return 'http://' + info.category + '.douban.com/' + info.type + '/' + info.id + '/';
}

douban.update_button = function (id, status, indicator) {
    var container = $($('div.article div.rec-sec span.rec')[0]);
    var button = container.children('a#' + id);

    if (button.length == 0) {
        var loading = chrome.extension.getURL('/assets/img/loading.gif');

        container.append("&nbsp;&nbsp;<a id='" + id + "' href='javascript:void(0);' class='lnk-douban-sharing'>" + status + "</a>");

        if (indicator) {
            container.append("<img id='loading' src='" + loading + "' style='display: none; height: 20px'>");
        }

        button = container.children('a#' + id);

    } else {
        button.text(status);
    }

    return button;
}

function set_overlay(){
    var oheight = ($.browser.msie?-2:16),
        dialog=$('#dialog')[0],
        w=dialog.offsetWidth,
        left=(document.body.offsetWidth-w)/2;

    $('#overlay').css({height:dialog.offsetHeight+oheight,width:w+16,left:left + 5 + 'px'});
    dialog.style.left=left+'px';
}

douban.show_dialog = function (div, w) {
    if($('#dialog').length) return;
    $('body').prepend('<div id="overlay"></div><div id="dialog" style="width:' + (w || 550) + 'px;"></div>');
    if(div != null){
        $('#dialog').html(div);
    }else{
        $('#dialog').html("<div class='loadpop'>正在载入，请稍候...</div>");
    }
    set_overlay();
};

douban.close_dialog = function () {
    $('#overlay').unbind('click');
    $('#dialog,#overlay,.bgi').remove();
    if (typeof document.body.style.maxHeight == "undefined") {//if IE6
        $('body','html').css({height: 'auto', width: 'auto'});
        $('html').css('overflow', '');
    }
    document.onkeydown = '';
    return false;
}

function viewport_size(){
    var size = [0, 0];
    if (typeof window.innerWidth != 'undefined'){
        size = [window.innerWidth, window.innerHeight];
    }else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0){
        size = [document.documentElement.clientWidth, document.documentElement.clientHeight];
    }else{
        size = [document.body.clientWidth, document.body.clientHeight];
    }
    return size;
}

douban.refine_dialog = function (){
    if (!$('#dialog').length) return;
    var agent = navigator.userAgent.toLowerCase();
    var top = 0.5 * (viewport_size()[1] - $('#dialog')[0].offsetHeight) + 140;
    $('#dialog,#overlay').css('top', top);
    set_overlay();
}

douban.create_api = function () {
    var api = new DOUBAN.DoubanApi(read_option('douban_api_key'),
                                   read_option('douban_api_key_secret'))

    api.access_token = read_option('douban_access_token');
    api.access_token_secret = read_option('douban_access_token_secret');

    return api;
}
    
})();